package com.haidechizi.util.retry.aop;

import com.haidechizi.util.retry.annotation.OptimisticLockRetry;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

/**
 * @author: wangdejun
 * @create: 2019-11-13 14:44
 **/
@Slf4j
@Aspect
public class OptimisticLockRetryAop {

    @Pointcut("@annotation(optimisticLockRetry)")
    public void pointCut(OptimisticLockRetry optimisticLockRetry) {

    }

    @Around("pointCut(optimisticLockRetry)")
    public Object around(ProceedingJoinPoint joinPoint, OptimisticLockRetry optimisticLockRetry) {
        try {
            int retryTimes = optimisticLockRetry.value();
            // 不进行重试
            if (retryTimes <= 1) {
                return joinPoint.proceed();
            }
            // 进行重试
            for (int i = 0; i < retryTimes; i++) {
                try {
                    // 是否进行延时重试
                    long retryInterval = optimisticLockRetry.retryInterval();
                    if (retryInterval > 0 && i > 0) {
                        optimisticLockRetry.timeunit().toSeconds(retryInterval);
                    }
                    return joinPoint.proceed();
                } catch (Throwable e) {
                    // 非重试异常，将异常抛出
                    if (e.getClass() != optimisticLockRetry.exception()) {
                        throw e;
                    }
                    log.error("执行失败，进行重试", e);
                }
            }
            // 在重试次数内执行失败，抛出异常
            throw new RuntimeException("重试失败");

        } catch (Throwable throwable) {
            log.error("Aop 执行异常", throwable);
            throw new RuntimeException(throwable);
        }
    }
}
